/*********************************************************************************
 *      Copyright:  (C) 2019 Wu Yujun<540726307@qq.com>
 *                  All rights reserved.
 *
 *       Filename:  Rectemper_server.c
 *    Description:  This file is receive temperature server
 *                 
 *        Version:  1.0.0(2019年01月22日)
 *         Author:  Wu Yujun <540726307@qq.com>
 *      ChangeLog:  1, Release initial version on "2019年01月22日 14时04分40秒"
 *                 
 ********************************************************************************/

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>          /*  See NOTES */
#include <sys/socket.h>
#include <libgen.h>
#include <unistd.h>
#include <getopt.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sqlite3.h>
#include "Rectemper_server.h"



int g_stop = 0 ;




void sig_handler(int sig_num)
{
    if(sig_num == SIGUSR1)
        g_stop = 1 ;
}


void print_usage(const char *program_name) 
{  
    printf("\n%s -- (2019.1.22)\n", program_name);  
    printf(" Usage: %s -p <server_port>  [-h <server_use_help>]\n", program_name);  
    printf("        -p --port       the server listen port\n") ;
    printf("        -h --help       the server file how to use\n");  
    printf("        -d --daemon     the server progame running in backgruand\n");  
                            
    return ;
}  


int main(int argc, char **argv)
{
    char                *program_name ;
    char                *ip = NULL ;
    char                *DB_NAME = "RPI_temper.db" ;
    int                 port = -1 ;
    int                 opt = -1 ;
    int                 daemon_run = 0 ;
    int                 log_fd = -1 ;
    int                 listen_fd = -1 ;
    char                rbuf[256] ;
    int                 rv = -1 ;
    int                 ep_fd ;
    struct epoll_event  ep_ev ;           
    struct epoll_event  ev_arr[MAX_EV] ; //have already even happened save in ev_arr
    int                 nready ;    
    int                 i ;
    int                 cli_fd = -1;
    int                 sock_fd ;
    char                sn[32] ;
    char                time[64] ;
    char                temper[32] ;
    sqlite3             *db ;

    
    program_name = basename(argv[0]) ;
            
    const char *short_opts = "i:p:hd";                    
    const struct option long_opts[] =   {  
        {"help", no_argument, NULL, 'h'},    
        {"ip", required_argument, NULL, 'i'},
        {"daemon", no_argument, NULL, 'd'},  
        { "port", required_argument, NULL, 'p'},  
        {0, 0, 0, 0} 
                                            }; 
    while ((opt= getopt_long(argc, argv, short_opts, long_opts,NULL)) != -1) 
    {
        switch (opt) 
        {
            case 'i':
                ip = optarg ;
                break ;
            case 'p':
                port = atoi(optarg) ;
                break ;
            case 'd':
                daemon_run = 1 ;
                break ;
            case 'h':
                print_usage(program_name) ;
                return 0 ;
            }
        }

    if( port < 0 )
    {
        print_usage(program_name) ;
        return -1 ;
    }
    if(daemon_run == 1)                      
    {
        printf("program %s running in backgrund\n", program_name);
        if( (log_fd = open("server.log", O_CREAT|O_RDWR, 0666)) < 0)
        {
            printf("open() failed:%s\n", strerror(errno)) ;
            return -2 ;
        }
        dup2(log_fd, STDOUT_FILENO) ;
        dup2(log_fd, STDERR_FILENO) ;
        daemon(1,1) ;
    }
    
    signal(SIGUSR1, sig_handler);

    listen_fd = CreatSocket(ip, port) ;
    if(listen_fd < 0)
    {
        printf("CreatSocket failed\n");
        return -3 ;
    }

    if( Opendb_create_table(DB_NAME, &db, "temperature") == ERROR) //Open RPI_temper.db
    {
            printf("Open db error!\n") ;
            return -4 ;
    }
    


    ep_fd = epoll_create(1024) ;
    if(ep_fd < 0)
    {
        printf("epoll_create() failed: %s\n", strerror(errno)) ;
        close(listen_fd) ;
        return -3 ;
    }
    printf("epoll_create sucessful, epfd[%d]\n", ep_fd) ;

    memset(&ep_ev, 0, sizeof(ep_ev)) ;
    ep_ev.data.fd = listen_fd ;
    ep_ev.events = EPOLLIN ;
    if( epoll_ctl(ep_fd, EPOLL_CTL_ADD, listen_fd, &ep_ev ) < 0)
    {
        printf("epoll_ctl() add listen_fd failed:%s\n", strerror(errno)) ;
    }


    while(!g_stop)
    {
    /*      timeout set -1 causes epoll_wait() to block indefinitely        */
        nready = epoll_wait(ep_fd, ev_arr, MAX_EV, -1); 
        if(nready < 0)
        {
            printf("epoll_wait failed: %s\n", strerror(errno)) ;
            continue ;
        }
        printf("the %d of file descriptors ready for the requested I/O\n", nready) ;
        for(i=0 ; i<nready; i++ )
        {
            if(ev_arr[i].events & EPOLLERR || ev_arr[i].events & EPOLLRDHUP )
            {
                printf("fd[%d] found error event: %s\n",ev_arr[i].data.fd ,strerror(errno)) ;
                epoll_ctl( ep_fd, EPOLL_CTL_DEL ,ev_arr[i].data.fd, NULL ) ;
                close(ev_arr[i].data.fd) ;
            }
            else if(ev_arr[i].data.fd == listen_fd) //have client want to connect 
            {
                    printf("Have client want to connect!\n") ;
                    cli_fd = Accept(listen_fd) ;
                    if( cli_fd < 0)
                    {
                        printf("Accept error\n") ;
                        continue ;
                    }
                    ep_ev.data.fd = cli_fd ;
                    ep_ev.events= EPOLLIN ;
                    if (epoll_ctl(ep_fd, EPOLL_CTL_ADD, cli_fd, &ep_ev) < 0)
                    {
                            printf("epoll_ctl add client[%d] failure: %s, will close client\n", cli_fd, strerror(errno)) ;
                            close(cli_fd) ;
                            continue ;
                    }
            }
            else //Already connected client have events 
            {
                printf("Already connect client have event come!\n") ;
                memset(rbuf, 0, sizeof(rbuf)) ;
                sock_fd = ev_arr[i].data.fd ;
                rv = read(sock_fd, rbuf, sizeof(rbuf)) ;
                if(rv <= 0)
                {
                        printf("read() error or client disconnect, close client[%d]!\n", sock_fd) ;
                        epoll_ctl(ep_fd, EPOLL_CTL_DEL, sock_fd, NULL) ;
                        close(sock_fd) ;
                        continue ;
                } 
                printf("%s\n", rbuf) ;
                memset(sn, 0, sizeof(sn)) ;
                memset(time, 0, sizeof(time)) ;
                memset(temper, 0, sizeof(temper)) ;
                analysis_temperinfo(rbuf, sn, time, temper) ;
                Insert_to_sqlite(db, sn, time, temper) ;
                
            }
        } //Traversal all happend events
        if(daemon_run) //if running in backgrund, client.log should be limited
        {
            log_roll_back(log_fd) ;
        } //    if(daemon_run)
    }// while(!g_stop)
    printf("Program  exit!\n") ;

    close(log_fd) ;
    return 0 ;
}

